classdef TestDotsAllObjectManagers < dotsTestCase
    
    properties
        manager;
        acknowledgementHappened;
        acknowledgedProperty;
        acknowledgedObject;
    end
    
    methods
        function self = TestDotsAllObjectManagers(name)
            self = self@dotsTestCase(name);
        end
        
        function setUp(self)
            self.setUp@dotsTestCase;
            dotsAllObjectManagersTestable.reset;
            self.manager = dotsAllObjectManagersTestable.theObject;
            self.acknowledgementHappened = false;
            self.acknowledgedProperty = '';
            self.acknowledgedObject = [];
        end
        
        function tearDown(self)
            self.tearDown@dotsTestCase;
        end
        
        function object = newManagedObject(self)
            object = self.manager.newObject('dotsAllManagedObjectsTestable');
        end
        
        function managerAcknowledgeFcn(self, object, property)
            self.acknowledgementHappened = true;
            self.acknowledgedProperty = property;
            self.acknowledgedObject = object;
        end
        
        function testAddRemoveManagedObject(self)
            group1 = 'test';
            obj1 = self.newManagedObject;
            self.manager.addObjectToGroup(obj1, group1);
            
            g = self.manager.getGroup(group1);
            assertEqual(obj1, g{1}, 'Manager group should contain new object');
            assertTrue(any(strcmp(obj1.groups, group1)), 'test object should know its group membership');
            
            obj2 = self.newManagedObject;
            self.manager.addObjectToGroup(obj2, group1);
            
            group2 = 'test2';
            self.manager.addObjectToGroup(obj2, group2);
            g = self.manager.getGroup(group2);
            assertEqual(obj2, g{1}, 'New manager group should contain new object');
            assertTrue(any(strcmp(obj2.groups, group1)), 'test object should know its multiple group membership');
            assertTrue(any(strcmp(obj2.groups, group2)), 'test object should know its multiple group membership');
            
            self.manager.removeObjectFromGroup(obj2, group2);
            g = self.manager.getGroup(group2);
            assertTrue(isempty(g), 'New manager group should no longer contain any object');
            assertFalse(any(strcmp(obj2.groups, group2)), 'test object should reflect its discontinued group membership');
            
            [g, UIDs] = self.manager.getAll;
            assertEqual(g{strcmp(UIDs, obj1.UID)}, obj1, 'Manager should contain object in default group');
            assertEqual(g{strcmp(UIDs, obj2.UID)}, obj2, 'Manager should contain second object in default group');
            
            self.manager.removeObject(obj1);
            self.manager.removeObject(obj2);
            g = self.manager.getGroup(group1);
            assertTrue(isempty(g), 'Manager group should no longer contain any object');
            assertTrue(isempty(obj1.groups), 'test object should have no group membership');
            assertTrue(isempty(obj2.groups), 'new test object should have no group membership');
            
            [g, UIDs] = self.manager.getAll;
            assertTrue(isempty(g), 'manger should have no more objects');
        end
        
        function testAcknowledgeObjectProperty(self)
            obj = self.newManagedObject;
            
            ackFcn = @(object, property)self.managerAcknowledgeFcn(object, property);
            self.manager.acknowledgePropertyChangeFunction = ackFcn;
            
            property = 'testProperty';
            value = 'whatever';
            obj.(property) = value;
            
            assertTrue(self.acknowledgementHappened, 'manger should have acknowledged that an object property changed')
            assertEqual(self.acknowledgedObject, obj, 'manger should have acknowledged which object''s property changed')
            assertEqual(self.acknowledgedProperty, property, 'manger should have acknowledged which property changed')
        end
        
        function testSetGetObjectProperty(self)
            obj = self.newManagedObject;
            
            property = 'testProperty';
            value = 'whatever';
            self.manager.setObjectProperty(obj, property, value);
            assertEqual(obj.(property), value, 'object should have received new property value')
            
            retrieved = self.manager.getObjectProperty(obj, property);
            assertEqual(retrieved, value, 'manager should return new property value')
        end
        
        function testSetGetGroupProperty(self)
            group = 'test';
            obj1 = self.newManagedObject;
            obj2 = self.newManagedObject;
            self.manager.addObjectToGroup(obj1, group);
            self.manager.addObjectToGroup(obj2, group);
            
            property = 'testProperty';
            value = 'whatever';
            self.manager.setGroupProperty(group, property, value);
            assertEqual(obj1.(property), value, 'first object should have received group property value')
            assertEqual(obj2.(property), value, 'second object should have received group property value')
        end
        
        function testCallObjectMethod(self)
            obj = self.newManagedObject;
            
            method = 'echoValue';
            value = 'whatever';
            self.manager.callObjectMethod(obj, method, value);
            assertEqual(obj.echo, value, 'object should have copied given value')
        end
        
        function testCallObjectMethodWithReturn(self)
            obj = self.newManagedObject;
            
            method = 'echoValue';
            value = 'whatever';
            returnProperty = 'returnValue';
            self.manager.callObjectMethodWithReturn(obj, returnProperty, method, value);
            assertEqual(obj.echo, value, 'object should have copied given value')
            assertEqual(obj.(returnProperty), value, 'manager should have assigned given value')
        end
        
        function testCallGroupMethod(self)
            group = 'test';
            obj1 = self.newManagedObject;
            obj2 = self.newManagedObject;
            self.manager.addObjectToGroup(obj1, group);
            self.manager.addObjectToGroup(obj2, group);
            
            method = 'echoValue';
            value = 'whatever';
            self.manager.callGroupMethod(group, method, value);
            assertEqual(obj1.echo, value, 'first object should have copied given value')
            assertEqual(obj2.echo, value, 'second object should have copied given value')
        end
        
        function testSetObjectPropertiesMany(self)
            obj = self.newManagedObject;
            
            batch = {'testProperty', 'test', 'returnValue', false};
            self.manager.setObjectPropertiesMany(obj, batch{:});
            
            for ii = 2:2:length(batch)
                property = batch{ii-1};
                value = batch{ii};
                assertEqual(obj.(property), value, ...
                    'should have set each property in the batch')
            end
        end
    end
end